package net.callumtaylor.asynchttp.response; import net.callumtaylor.asynchttp.AsyncHttpClient.ClientExecutorTask; import net.callumtaylor.asynchttp.obj.ConnectionInfo; import net.callumtaylor.asynchttp.obj.Packet; import java.io.InputStream; import java.net.SocketTimeoutException; /** * This is the base class for response handlers in AsyncHttpClient. The method * flow is as follows: * * <pre> * onSend -> onPublishedUploadProgress -> onPublishedDownloadProgress -> beforeCallback -> onSuccess/onFailure -> beforeFinish -> onFinish * </pre> * * {@link AsyncHttpResponseHandler#onPublishedDownloadProgress}, {@link AsyncHttpResponseHandler#onPublishedUploadProgress}, * {@link AsyncHttpResponseHandler#beforeCallback}, {@link AsyncHttpResponseHandler#onSuccess}, and {@link AsyncHttpResponseHandler#onFailure} all run in * the background thread. All your processing should be handled in one of those * 4 methods and then either call to run on UI thread a new runnable, or handle * in {@link AsyncHttpResponseHandler#onFinish} which runs on the UI thread * * In order to get the content created from the response handler, you must * call {@link AsyncHttpResponseHandler#getContent} which can be accessed in {@link AsyncHttpResponseHandler#onSuccess} or * {@link AsyncHttpResponseHandler#onFailure} */ public abstract class AsyncHttpResponseHandler { private final ConnectionInfo connectionInfo = new ConnectionInfo(); public ConnectionInfo getConnectionInfo() { return connectionInfo; } /** * Called when the connection is first made */ public void onSend(){} /** * Called when processing the response from a stream. Use this to override * the processing of the InputStream to handle the response differently. * Default is to read the response as a byte-array which gets passed, chunk * by chunk, to {@link AsyncHttpResponseHandler#onPublishedDownloadProgress} * * @param stream * The response InputStream * @param client * The client task. In order to call * {@link AsyncHttpResponseHandler#onPublishedDownloadProgressUI}, you must call * <code>client.postPublishProgress(new Packet(int readCount, int totalLength, boolean isDownload))</code> * This is required when displaying a progress indicator. * @param totalLength * The total length of the stream * @throws SocketTimeoutException * @throws Exception */ public void onBeginPublishedDownloadProgress(InputStream stream, ClientExecutorTask client, long totalLength) throws SocketTimeoutException, Exception { byte[] buffer = new byte[8196]; int len = 0; int readCount = 0; while ((len = stream.read(buffer)) > -1 && !client.isCancelled()) { onPublishedDownloadProgress(buffer, len, totalLength); onPublishedDownloadProgress(buffer, len, readCount, totalLength); client.postPublishProgress(new Packet(readCount, totalLength, true)); readCount += len; } if (!client.isCancelled()) { getConnectionInfo().responseLength = readCount; // we fake the content length, because it can be -1 onPublishedDownloadProgress(null, readCount, readCount); onPublishedDownloadProgress(null, readCount, readCount, readCount); client.postPublishProgress(new Packet(readCount, totalLength, true)); } stream.close(); } /** * Called when a chunk has been downloaded from the request. This will be * called once every chunk request, and once extra when all the content is * downloaded. * * @param chunk * The chunk of data. This will be the <b>null</b> after the total amount has been downloaded. * @param chunkLength * The length of the chunk * @param totalLength * The total size of the request. <b>note:</b> This <i>can</i> be * -1 during download. */ public void onPublishedDownloadProgress(byte[] chunk, int chunkLength, long totalLength){} /** * Called when a chunk has been downloaded from the request. This will be * called once every chunk request, and once extra when all the content is * downloaded. * * @param chunk * The chunk of data. This will be the <b>null</b> after the total amount has been downloaded. * @param chunkLength * The length of the chunk * @param totalProcessed * The total amount of data processed from the request. * @param totalLength * The total size of the request. <b>note:</b> This <i>can</i> be * -1 during download. */ public void onPublishedDownloadProgress(byte[] chunk, int chunkLength, long totalProcessed, long totalLength){} /** * Runs on the UI thread. Useful for updating progress bars. * * @param totalProcessed * The total processed sized of the request * @param totalLength * The total length of the request */ public void onPublishedDownloadProgressUI(long totalProcessed, long totalLength){} /** * Called when a chunk has been uploaded to the request. This will be * called once every chunk request * * @param chunk * will be the total byte array when this is called. * @param chunk * The chunk of data * @param chunkLength * The length of the chunk * @param totalLength * The total size of the request. */ public void onPublishedUploadProgress(byte[] chunk, int chunkLength, long totalLength){} /** * Called when a chunk has been uploaded to the request. This will be * called once every chunk request * * @param chunk * will be the total byte array when this is called. * @param chunk * The chunk of data * @param chunkLength * The length of the chunk * @param totalProcessed * The total amount of data processed from the request. * @param totalLength * The total size of the request. */ public void onPublishedUploadProgress(byte[] chunk, int chunkLength, long totalProcessed, long totalLength){} /** * Runs on the UI thread. Useful for updating progress bars. * * @param totalProcessed * The total processed sized of the request * @param totalLength * The total length of the request */ public void onPublishedUploadProgressUI(long totalProcessed, long totalLength){} /** * Called just before {@link AsyncHttpResponseHandler#onSuccess} */ public void beforeCallback(){} /** * Override this method to efficiently generate your content from any buffers you have have * used. * * This is called directly after {@link AsyncHttpResponseHandler#onBeginPublishedDownloadProgress} has finished */ public abstract void generateContent(); /** * Gets the content generated from the * response. * * You should only call this once * * @return The generated content object */ public abstract Object getContent(); /** * Processes the response from the stream. * This is <b>not</b> ran on the UI thread * * @return The modified data set, or null */ public abstract void onSuccess(); /** * Called when a response was not 2xx. * * @return The modified data set, or null */ public void onFailure(){} /** * Called before {@link AsyncHttpResponseHandler#onFinish} */ public void beforeFinish(){} /** * Called when the streams have all finished, success or not */ public void onFinish(){} /** * Called when the streams have all finished, success or not * * @param failed * If the stream failed or not. Useful to display any UI updates * here. */ public void onFinish(boolean failed){} }